package mammuthus.master.docker

import mammuthus.master.Master
import mammuthus.template.DockerCommand
import akka.pattern.ask
import net.csdn.common.env.Environment
import java.io.File
import mammuthus.protocal._
import mammuthus.slave.InteractiveShellCommand
import mammuthus.protocal.DockerRequest
import mammuthus.docker.protocal.ListContainerRequest
import mammuthus.docker.protocal.ListContainerResponse
import mammuthus.protocal.ExecuteBlockShellCommandRequest
import mammuthus.protocal.ExecuteShellCommandRequest
import mammuthus.protocal.ExecuteShellCommandResponse
import mammuthus.docker.protocal.StopContainerResponse
import scala.collection.mutable

/**
 * 5/6/15 WilliamZhu(allwefantasy@gmail.com)
 */
trait DockerOperation extends DockerCommand {
  this: Master =>

  def jdkName = {
    "jdk1.7.0_05.tar.gz"
  }

  def agentName = {
    "mammuthus-agent-1.0.0.tar.gz"
  }

  def installRepo(hostName: String, tt: Long) = {
    require(!hostName.contains(","))
    executeShellCommand(hostName, dockerCommandRender("installRepo"), tt)
  }


  def dockerContainerList(hostNames: String) = {
    _remoteExecute[ListContainerResponse](hostNames, (ar, hostName) => {
      ar ? DockerRequest(ListContainerRequest(hostName))
    })
  }

  def dockerContainerStart(hostNames: String, id: String) = {
    val command = dockerCommandRender("dockerStart", Map("id" -> id))
    //    _remoteExecute[StartContainerResponse](hostNames, (ar, hostName) => {
    //      ar ? DockerRequest(StartContainerRequest(hostName, id))
    //    })
    executeBlockShellCommand(hostNames, command)
    List(StopContainerResponse(hostNames, true, id, "", ""))
  }

  def dockerContainerStop(hostNames: String, id: String) = {
    //    _remoteExecute[StopContainerResponse](hostNames, (ar, hostName) => {
    //      ar ? DockerRequest(StopContainerRequest(hostName, id))
    //    })
    val command = dockerCommandRender("dockerStop", Map("id" -> id))
    executeBlockShellCommand(hostNames, command)
    List(StopContainerResponse(hostNames, true, id, "", ""))
  }

  def run(hostNames: String, imageName: String, containerName: String, masterIP: String, netType: String, changeHostName: Boolean,params:java.util.Map[String,String]) = {
    import scala.collection.JavaConversions._
    val options = params.filter(f=>f._1.startsWith("--") && f._1 != "--net=none").map(f=>s"${f._1} ${f._2}").mkString(" ")
    val command = dockerCommandRender("dockerRun", Map("imageName" -> imageName, "name" -> containerName, "MASTER_IP" -> masterIP,
      "MASTER_HOST" -> masterHost,
      "net" -> netType,
      "hostname" -> (if (changeHostName) s"-h $containerName" else ""),
      "runAgent" -> (if (netType == "--net=none") "/bin/bash" else ""),
      "interactive" -> (if (netType == "--net=none") "-it" else ""),
      "options" -> options
    ))
    logger.info(command)
    executeShellCommand(hostNames, command, InteractiveShellCommand.defaultTimeOut)
  }

  import net.liftweb.{json => SJSon}

  implicit val formats = SJSon.Serialization.formats(SJSon.NoTypeHints)

  def buildDockerAgent(hostNames: String, agentPort: String, sourceImage: String, targetImage: String, skipDownload: Boolean = false) = {
    val env = new Environment(_conf)
    val resourceDir = env.templateDirFile().getPath + "/assets"

    require(new File(resourceDir + "/" + jdkName).exists(), s"$jdkName not found in master")
    require(new File(resourceDir + "/" + agentName).exists(), s"$agentName not found in master")

    val dockerFile = dockerCommandRender("buildAgent", Map(
      "installDir" -> "/data/1/usr/local",
      "agentPort" -> agentPort,
      "agentName" -> agentName,
      "sourceImage" -> sourceImage,
      "targetImage" -> targetImage,
      "jdkName" -> jdkName
    ))
    val dockerMakeFileDir = "/data/1/usr/local/docker"
    val appName = "mammuthus-agent"


    executeBlockShellCommand(hostNames, s"mkdir -p $dockerMakeFileDir/$appName")
    if (!skipDownload) {
      val jdkDownload = blockDownload(hostNames, s"http://$masterHost:${masterHttpPort}/$jdkName", s"$dockerMakeFileDir/$appName/$jdkName")
      val agentDownload = blockDownload(hostNames, s"http://$masterHost:${masterHttpPort}/$agentName", s"$dockerMakeFileDir/$appName/$agentName")
      val jdkError = jdkDownload.filterNot(f => f.success)
      val agentError = agentDownload.filterNot(f => f.success)

      require(jdkError.size == 0 && agentError.size == 0, SJSon.Serialization.write(List(jdkError, agentError)))
    }

    writeFile(hostNames, dockerFile, s"$dockerMakeFileDir/$appName/Dockerfile", false)

    val buildAgentShell = dockerCommandRender("buildAgentShell", Map(
      "dockerMakeFileDir" -> dockerMakeFileDir,
      "appName" -> appName,
      "imageName" -> targetImage
    ))

    executeShellCommand(hostNames, buildAgentShell, InteractiveShellCommand.defaultTimeOut)
  }


  def configDockerIp(hostNames: String, brName: String, containerName: String, containerIP: String, gatewayIP: String): mutable.ArraySeq[ExecuteShellCommandResponse] = {
    val check = executeBlockShellCommand(hostNames, s"""docker exec $containerName /bin/bash -c "ip addr || ipconfig"""")

    logger.info(check.map(f=>f.message).mkString("\n"))

    if (check.filter(f => f.message.contains(containerIP)).size != 0) {
     throw new RuntimeException(s"ip $containerIP in $containerName have been configured")
    }



    val dockerIp = dockerCommandRender("configDockerNetwork", Map(
      "brName" -> brName,
      "containerName" -> containerName,
      "containerIP" -> containerIP,
      "gatewayIP" -> gatewayIP
    ))
    logger.info(dockerIp)
    executeShellCommand(hostNames, dockerIp, InteractiveShellCommand.defaultTimeOut)
  }


  def configHostNetwork(hostNames: String, eth: String, gatewayIP: String): List[ExecuteShellCommandResponse] = {
    //检查是不是有服务器已经配置过网络
    val fakeToken = "-"
    val res = _remoteExecute[ExecuteBlockShellCommandResponse](hostNames, (ar, hostName) => {
      val command = "ifconfig"
      ar ? ExecuteBlockShellCommandRequest(ExecuteShellCommandRequest(hostName, command, fakeToken, 3000))
    }).filter {
      f =>
        f.message.contains("mammuthusbr0")
    }.map(f => ExecuteShellCommandResponse(ShellTask(fakeToken, f.hostName), "bridge mammuthusbr0 have been set.now this api only support first time congiuring")).toList

    if (res.size > 0) return res

    //检查是不是命令都齐备了
    List("ip","brctl","route")

    val token = tokenGenerate
    _remoteExecute[ExecuteShellCommandResponse](hostNames, (ar, hostName) => {
      val command = dockerCommandRender("configHostNetwork", Map(
        "hostIP" -> slaves(hostName)._2.ip.filter(f => f.name == eth).map(f => f.ipv4).toList(0),
        "eth" -> eth,
        "gatewayIP" -> gatewayIP,
        "brName" -> "mammuthusbr0"
      ))
      logger.info(s"configure network: $command")
      ar ? ExecuteShellCommandRequest(hostName, command, token, 3000)
    }).toList
  }
}
